<template>
  <form class="validate-form-container">
    <!-- input区域设置成默认 -->
    <slot name="default"></slot>
    <!-- 提交区域 -->
    <div class="submit-area" @click.prevent="submitForm">
      <slot name="submit">
        <!-- 加入没有填充进来的时候使用默认的内容 -->
        <button type="submit" class="btn btn-primary">
          提交
        </button>
      </slot>
    </div>
  </form>
</template>

<script lang="ts">
import { defineComponent, onMounted, onUnmounted, ref } from "vue";
import mitt from "mitt";

// 1. 测试：定义一个events类型，让事件和对应的callback一一对应
// type 关键字是可以给类型起一个别名 ValidateFunc类型没有形参返回一个布尔值
type ValidateFunc = () => boolean;
// new
type ClearFunc = () => void;

// mitt
type Events = {
  "form-item-created": ValidateFunc;
  "form-item-clear": ClearFunc;
};
// 2. 实例化mitt 新建监听器emitter，将events作为泛型传递出去
export const emitter = mitt<Events>();

export default defineComponent({
  name: "ValidateForm",
  emits: ["form-submit"],
  setup(props, context) {
    // formRef
    // const formRef = ref<any>();

    // 6. 数组存放的是ValidateFunc类型的函数 也就是ValidateInput组件发送事件的时候带着发送出来的验证函数
    // 数组中存放着信息，并返回input是否通过
    let funcArr: ValidateFunc[] = [];
    let clearFuncArr: ClearFunc[] = [];

    const submitForm = () => {
      // 7. 循环调用存放着每个ValidateInput组件的验证函数的数组 funcArr 并且返回最终值result
      // funcArr.map(func => func())是一个装满了Input验证结果布尔值的数组
      // 接着.every() 返回最终验证结果（every有一个为假就会打断并返回假）
      const result = funcArr
        .map(func => func())
        .every(res => {
          return res;
        });
      // 把所有的Input组件的验证结果都汇总起来发送事件'form-submit'，App中会监听这个事件
      context.emit("form-submit", result);
    };
    // 3. 事件监听器的回调  传入Input中通过事件'form-item-created'发送出来的的验证函数
    // 定义为ValidateFunc类型
    const callback = (func: ValidateFunc) => {
      funcArr.push(func); // 把所有的函数添加到数组中
    };

    const callback2 = (func: ClearFunc) => {
      clearFuncArr.push(func); // 把所有的函数添加到数组中
    };

    const clearInputs = () => {
      clearFuncArr.forEach(func => {
        func();
      });
    };

    // 4. on添加到监听器中，监听事件'form-item-created'，事件触发了之后会调用回调函数callback
    emitter.on("form-item-created", callback);
    emitter.on("form-item-clear", callback2);

    onUnmounted(() => {
      // 5. 组件卸载的时候清理工作
      emitter.off("form-item-created", callback);
      emitter.off("form-item-clear", callback2);
      funcArr = [];
      clearFuncArr = [];
    });
    return {
      submitForm,
      clearInputs
      // formRef
    };
  }
});
</script>

<style lang="less" scoped>
.submit-area {
  width: fit-content;
  margin: auto;
}
</style>
